#pragma once
#include "../engine/viewport.h"
#include "../math/meshobject.h"

class Surface;
struct Vector4;

// ================================================================================================
// Container that holds sampling information
// ================================================================================================
class SimpleContainer {

private:

    MeshObject* mobject;
    Viewport* viewport;
    uint numsurfaces;
    Rect2D rect;
    bool* kill;
    bool* ticket;
    bool* refresh;
    bool* finished;

public:

    // -- default constructor
    SimpleContainer();

    // -- constructor
    SimpleContainer(MeshObject*&);

    // -- accessor methods
    MeshObject*& GetMesh();
    MeshObject* const & GetMesh() const;
    uint GetNumSurfaces();
    Viewport*& GetViewport();
    Viewport* const& GetViewport() const;
    Rect2D& GetRect();
    const Rect2D& GetRect() const;
    bool*& GetKill();
    bool* const& GetKill() const;
    bool*& GetTicket();
    bool* const& GetTicket() const;
    bool*& GetFinished();
    bool* const& GetFinished() const;
    bool*& GetRefresh();
    bool* const& GetRefresh() const;

    // -- mutator methods
    void SetMeshes();
    void SetNumSurfaces(uint num);
    void SetIndexStart(uint indexstart);
    void SetIndexEnd(uint indexend);

    // -- Public interface
    template<uint size> friend void DivideBuffer(SimpleContainer (&)[size], 
                                                MeshObject* mobject, Viewport* viewport, 
                                                Rect2D& rect, bool tickets[][4]);               
    template<uint size> friend void SetMeshes(SimpleContainer* container, MeshObject* mobject);
};

// ================================================================================================
// Constructors
// ================================================================================================
inline SimpleContainer::SimpleContainer() {
}

inline SimpleContainer::SimpleContainer(MeshObject*& mobject_) : mobject(mobject_){
}

// ================================================================================================
// Accessor Methods
// ================================================================================================
inline MeshObject*& SimpleContainer::GetMesh() {
    return mobject;
}
inline MeshObject* const & SimpleContainer::GetMesh() const {
    return mobject;
}

inline uint SimpleContainer::GetNumSurfaces() {
    return numsurfaces;
}

inline Viewport*& SimpleContainer::GetViewport() {
    return viewport;
}

inline Viewport* const& SimpleContainer::GetViewport() const {
    return viewport;
}

inline Rect2D& SimpleContainer::GetRect() {
    return rect;
}

inline const Rect2D & SimpleContainer::GetRect() const {
    return rect;
}

inline bool*& SimpleContainer::GetKill() {
    return kill;
}

inline bool* const& SimpleContainer::GetKill() const {
    return kill;
}

inline bool*& SimpleContainer::GetTicket() {
    return ticket;
}

inline bool* const& SimpleContainer::GetTicket() const {
    return ticket;
}

inline bool*& SimpleContainer::GetFinished() {
    return finished;
}

inline bool* const& SimpleContainer::GetFinished() const {
    return finished;
}

inline bool*& SimpleContainer::GetRefresh() {
    return refresh;
}

inline bool* const& SimpleContainer::GetRefresh() const {
    return refresh;
}

// =================================================================================================
// Mutator methods
// =================================================================================================
inline void SimpleContainer::SetNumSurfaces(uint num) {
    numsurfaces = num;
}

// =================================================================================================
//  Function that tasks divisions of a buffer to container
// =================================================================================================
template<uint size> void DivideBuffer(SimpleContainer (&arr)[size], Viewport* viewport, 
                                      Rect2D& rect, bool tickets[][4]) {

    Rect2D temprect;
    temprect.topleft.x = 0;
    temprect.topleft.y = 0;
    temprect.bottomright.x = rect.bottomright.x;
    temprect.bottomright.y = rect.bottomright.y / size;

    Point2D tempstep;
    tempstep.x = 0;
    tempstep.y = temprect.bottomright.y;

    for(uint i = 0; i < size; ++i) {
        arr[i].GetViewport() = viewport;
        tickets[0][0] = false;
        arr[i].GetKill() = &tickets[0][0];
        arr[i].GetRect() = temprect;
        temprect += tempstep;
        tickets[i][1] = false;
        arr[i].GetTicket() = &tickets[i][1];
        tickets[i][2] = false;
        arr[i].GetFinished() = &tickets[i][2];
        tickets[i][3] = true;
        arr[i].GetRefresh() = &tickets[i][3];
    }
}

// ================================================================================================
// Function that sets the containers to the meshobject designated
// ================================================================================================
template<uint size> void SetMeshes(SimpleContainer (&arr)[size], MeshObject* mobject) {
    for(uint i = 0; i < size; ++i) {
        arr[i].GetMesh() = mobject;
        arr[i].SetNumSurfaces(mobject->GetNumFaces());
    }
}